<?php
/**
 * 服务端定义了wsdl文件
 * 客户端以wsdl方式请求  根据wsdl再请求服务端的soap脚本 是可以不指定wsdl脚本的
 */


class ExampleService {
    public function add($a, $b) {
        return $a + $b;
    }
}

$wsdl = 'http://localhost/soap/wsdl_server.php?wsdl';
$namespace = "http://example.com/soap";
$className = ExampleService::class;
$serviceUrl = 'http://localhost/soap/wsdl_server.php';

// 检查请求的 URI
if (isset($_GET['wsdl'])) {
    // 返回 WSDL 文件
    header('Content-Type: text/xml');
    echo generateWsdl($className, $namespace, $serviceUrl);
} else {
    // 创建 SOAP 服务器脚本
    $server = new SoapServer($wsdl);
    //$server = new SoapServer(null, ['uri' => "http://example.com/soap"]);
    $server->setClass($className);
    $server->handle();
}

// 生成 WSDL 文件的函数
function generateWsdl($serviceUrl, $namespace, $className) {
    $wsdl = '<?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
                 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                 xmlns:tns="{namespace}"
                 targetNamespace="{namespace}"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema" >

        <message name="AddRequest">
            <part name="a" type="xsd:int"/>
            <part name="b" type="xsd:int"/>
        </message>

        <message name="AddResponse">
            <part name="result" type="xsd:int"/>
        </message>

        <portType name="ExamplePortType">
            <operation name="add">
                <input message="tns:AddRequest"/>
                <output message="tns:AddResponse"/>
            </operation>
        </portType>

        <binding name="ExampleBinding" type="tns:ExamplePortType">
            <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
            <operation name="add">
                <soap:operation soapAction="{namespace}/soap/add"/>
                <input>
                    <soap:body use="literal"/>
                </input>
                <output>
                    <soap:body use="literal"/>
                </output>
            </operation>
        </binding>

        <service name="ExampleService">
            <port name="ExamplePort" binding="tns:ExampleBinding">
                <soap:address location="{serviceUrl}"/>
            </port>
        </service>
    </definitions>';
    $wsdl = strtr($wsdl, ['{serviceUrl}' => $serviceUrl, '{namespace}' => $namespace]);
    return $wsdl;
}

//WSDL 文件的 URL：在 WSDL 中，确保将 <soap:address> 中的 location 属性替换为实际服务的 URL。